# -*-coding utf-8 -*-

__project__ = 'le-bo16'
__file_name__ = 'class13'
__author__ = 'hqDu'
__time__ = '2020-11-27 22:22'
__product_name = 'PyCharm'
# @fileName :class13.py


"""
2.5 子类重写父类的同名属性和方法
"""
"""
大猫掌握了 师傅的配方 和 学校的配方，通过研究，大猫在两个配方的基础上，
创建了一种全新的煎饼果子配方，称之为 "猫氏煎饼果子配方"。
（子类重写父类同名属性和方法）
"""
# 师傅
# class Master(object):
#     def __init__(self):
#         self.peifang = '古法配方'
#     def make_cake(self):
#         print('制作古法煎饼')
#
#     def aaa(self):
#         print('aaa')
#
# # 自创
# class School(object):
#     def __init__(self):
#         self.peifang = '现代配方'
#
#     def make_cake(self):
#         print("现代配方")
#
#     def bb(self):
#         print('bbb')
#
# # 徒弟
#
# class Prentice(Master, School):
#
#     # 子类重写父类的同名属性和方法
#     def __init__(self):  # 此处__init__高亮是因为，Master和School里面也有__init__方法
#         self.peifang = '猫式'
#
#     # 子类重写父类的同名属性和方法
#     def make_cake(self):
#         print("制作猫式煎饼")
#
#
# damao = Prentice()
# print(damao.peifang)
# damao.make_cake()
# # 子类的魔法属性__mro__决定了，子类对象调用属性和方法的查找顺序
# print(Prentice.__mro__)


"""
2.6 子类调用父类的同名属性和方法
大猫的新配方大受欢迎，
但是有些顾客希望也能吃到古法配方和 现代配方 的煎饼果子...
"""

# 师傅
# class Master(object):
#     def __init__(self):
#         self.kongfu = '古法配方'
#     def make_cake(self):
#         print("[古法] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)
#
#     def aaa(self):
#         print('aaa')
#
# # 自创
# class School(object):
#     def __init__(self):
#         self.kongfu = '现代配方'
#
#     def make_cake(self):
#         print("[现代] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)
#
#     def bb(self):
#         print('bbb')
#
# # 徒弟
# class Prentice(Master, School):
#
#     # 子类重写父类的同名属性和方法
#     def __init__(self):  # 此处__init__高亮是因为，Master和School里面也有__init__方法
#         self.kongfu = '猫式'
#         # 子类调用父类的属性，在__init__里只可以调用一个同名属性
#         # School.__init__(self)  # School的同名属性覆盖了Prentice的属性
#
#     # 子类重写父类的同名属性和方法
#     def make_cake(self):
#         print("执行子类的__init__方法前，self.kongfu属性：%s" % self.kongfu)
#         self.__init__()  # 执行本类的__init__方法，做属性初始化 self.kongfu = "猫氏...."
#         print("执行子类的__init__方法前，self.kongfu属性：%s" % self.kongfu)
#         print("[猫氏] 按照 <%s> 制作了一份煎饼果子..." % self.kongfu)
#         # print("制作猫式煎饼")
#
#     # 子类调用父类的同名方法和属性
#     # 调用父类方法格式：父类类名.父类的同名方法(self)  父类名.同名方法名(self)
#     def make_old_cake(self):
#         print("执行School的__init__方法之前，self.kongfu属性：%s" % self.kongfu)
#         School.__init__(self)
#         print("执行School的__init__方法之后，self.kongfu属性：%s" % self.kongfu)
#         School.make_cake(self)
#         # School.__init__(self)
#
#     def make_old1_cake(self):
#         print("执行Master的__init__方法之前，self.kongfu属性：%s" % self.kongfu)
#         Master.__init__(self)
#         print("执行Master的__init__方法之后，self.kongfu属性：%s" % self.kongfu)
#         Master.make_cake(self)
#
#
#
# damao = Prentice()
# print(damao.kongfu)
# damao.make_cake()
# damao.make_old_cake()
# damao.make_old1_cake()
# damao.make_cake()
# # 子类的魔法属性__mro__决定了，子类对象调用属性和方法的查找顺序
# print(Prentice.__mro__)

"""
无论何时何地，self都表示是子类的对象。
在调用父类方法时，通过传递self参数，来控制方法和属性的访问修改。
"""



"""
2.8 super()继承父类的方法
使用super()可以逐一调用所有的父类方法，并且只执行一次。调用顺序遵循mro魔法属性中类的顺序。
注意（特点）：如果继承了多个父类，并且父类都具有同名方法，则默认只执行第一个父类的同名方法。
通常用于单继承的多层继承
"""

# # 师傅
# class Master(object):
#     def __init__(self):
#         self.peifang = '古法配方'
#     def make_cake(self):
#         print('制作古法煎饼')
#
#     def aaa(self):
#         print('aaa')
#
# # 自创
# class School(object):
#     def __init__(self):
#         self.peifang = '现代配方'
#
#     def make_cake(self):
#         print("现代配方")
#
#     def bb(self):
#         print('bbb')
#
# # 徒弟
#
# class Prentice(Master, School):
#
#     # 子类重写父类的同名属性和方法
#     def __init__(self):  # 此处__init__高亮是因为，Master和School里面也有__init__方法
#         self.peifang = '猫式'
#
#     # 子类重写父类的同名属性和方法
#     def make_cake(self):
#         print("制作猫式煎饼")
#
#     # 子类继承父类的同名方法名
#     # super()只能继承第一个父类的同名方法
#     def make_old_cake(self):
#         # 子类继承父类的同名方法的方式：
#         # 方法1：可以通过类名指定调用哪个父类的同名方法
#         # Master.make_cake(self)  # 子类继承了多个父类，如果父类类名修改了，那么子类也要涉及多次修改。而且需要重复写多次调用，显得代码臃肿。
#         # 方法2：super(子类名, self).父类的同名方法
#         # super(Prentice, self).make_cake()
#         # 方法3：
#         super().make_cake()
#
#
# damao = Prentice()
# print(damao.peifang)
# damao.make_cake()
# damao.make_old_cake()
# # 子类的魔法属性__mro__决定了，子类对象调用属性和方法的查找顺序
# print(Prentice.__mro__)


"""
2.7 多层继承
大猫的煎饼果子店非常红火，终于有一天，他成了世界首富！！
但是他也老了，所以他希望把 师傅的配方 和 学校的配方 以及自己的配方 继续传承下去...
"""

# # 师傅
# class Master(object):
#     def __init__(self):
#         self.peifang = '古法配方'
#     def make_cake(self):
#         print('制作古法煎饼')
#
#     def aaa(self):
#         print('aaa')
#
# # 自创
# class School(object):
#     def __init__(self):
#         self.peifang = '现代配方'
#
#     def make_cake(self):
#         print("现代配方")
#
#     def bb(self):
#         print('bbb')
#
# # 徒弟
#
# class Prentice(Master, School):
#
#     # 子类重写父类的同名属性和方法
#     def __init__(self):  # 此处__init__高亮是因为，Master和School里面也有__init__方法
#         self.peifang = '猫式'
#
#     # 子类重写父类的同名属性和方法
#     def make_cake(self):
#         print("制作猫式煎饼")
#
#     # 子类继承父类的同名方法名
#     # super()只能继承第一个父类的同名方法
#     def make_old_cake(self):
#         # 子类继承父类的同名方法的方式：
#         # 方法1：可以通过类名指定调用哪个父类的同名方法
#         # Master.make_cake(self)  # 子类继承了多个父类，如果父类类名修改了，那么子类也要涉及多次修改。而且需要重复写多次调用，显得代码臃肿。
#         # 方法2：super(子类名, self).父类的同名方法
#         # super(Prentice, self).make_cake()
#         # 方法3：
#         super().make_cake()
#
# class PrenticePrentice(Prentice):
#     pass
#
#
# pp = PrenticePrentice()
# pp.make_cake()
# pp.make_old_cake()
# # 子类的魔法属性__mro__决定了，子类对象调用属性和方法的查找顺序
# print(Prentice.__mro__)



"""
私有权限：
大猫觉得配方传承下去没问题，但是钱是辛辛苦苦挣得血汗钱，不想传给徒弟。（私有权限）

私有权限：在属性和方法前面添加两个下划线__

1.类的私有属性 和 私有方法，都不能通过对象直接访问，但是可以在本类内部访问；(对象不能访问私有权限的属性和方法)
2.类的私有属性 和 私有方法，都不会被子类继承，子类也无法访问；(子类不能继承父类私有权限的属性和方法)
3.私有属性 和 私有方法 往往用来处理类的内部事情，不通过对象处理，起到安全作用。
在类内部，在非私有的方法内，可以通过self.私有属性 self.私有方法，进而处理内部事务
不可以直接调用私有方法和属性
"""

# # 师傅
# class Master(object):
#     def __init__(self):
#         self.peifang = '古法配方'
#     def make_cake(self):
#         print('制作古法煎饼')
#
#     def aaa(self):
#         print('aaa')
#
# # 自创
# class School(object):
#     def __init__(self):
#         self.peifang = '现代配方'
#
#     def make_cake(self):
#         print("现代配方")
#
#     def bb(self):
#         print('bbb')
#
# # 徒弟
#
# class Prentice(Master, School):
#
#     # 子类重写父类的同名属性和方法
#     def __init__(self):  # 此处__init__高亮是因为，Master和School里面也有__init__方法
#         self.peifang = '猫式'
#         # 私有属性
#         self.__money = 1000
#
#     # 私有方法
#     def __aaa(self):
#         print("aaaa")
#
#     # 子类重写父类的同名属性和方法
#     def make_cake(self):
#         print("制作猫式煎饼")
#         # 在类内部，self.私有属性
#         print("money: %f" % self.__money)
#         # 在类内部，self.私有方法
#         self.__aaa()
#
#     # 子类继承父类的同名方法名
#     # super()只能继承第一个父类的同名方法
#     def make_old_cake(self):
#         # 子类继承父类的同名方法的方式：
#         # 方法1：可以通过类名指定调用哪个父类的同名方法
#         # Master.make_cake(self)  # 子类继承了多个父类，如果父类类名修改了，那么子类也要涉及多次修改。而且需要重复写多次调用，显得代码臃肿。
#         # 方法2：super(子类名, self).父类的同名方法
#         # super(Prentice, self).make_cake()
#         # 方法3：
#         super().make_cake()
#
#
#
# class  PrenticePrentice(Prentice):
#     pass
#
# damao = Prentice()
# damao.make_cake()
# print(damao.__money)
# damao.__aaa()


# pp = PrenticePrentice()
# print(pp.__money)
# pp.__aaa()

# 子类的魔法属性__mro__决定了，子类对象调用属性和方法的查找顺序
# print(Prentice.__mro__)

"""
封装：隐藏内部实现细节，只需要通过对象调用其属性或方法实现一些操作
意义：
1.将属性和方法放到一起做为一个整体，然后通过实例化对象来处理；
2.隐藏内部实现细节，只需要和对象及其属性和方法交互就可以了；
3.对类的属性和方法增加 访问权限控制。
"""

"""
修改私有属性的值
非私有属性也可以这样改值
"""
# class Dog(object):
#     def __init__(self):
#         self.__color = 'red'
#
#     # 使用私有属性并修改其值
#     def make(self):
#         return self.__color
#
#     def set_color(self,new_color):
#         self.__color = new_color
#
# dog = Dog()
# print(dog.make())
# dog.set_color('black')
# print(dog.make())




"""
多态：定义时类型和运行时类型可以不一致
承载于继承之后的，对象可以属于多个类型，简化代码
"""

# class Animal(object):
#     def run(self):
#         print('Animal')
#
# class Dog(Animal):
#     def __init__(self):
#         self.__color = 'red'
#
#     def run(self):
#         print('dog')
#
#     # 使用私有属性并修改其值
#     def make(self):
#         return self.__color
#
#     def set_color(self,new_color):
#         self.__color = new_color
#
# a = Dog()
# # 同一个对象，既可以是Dog类型，也可以是Animal类型
# print(isinstance(a,Dog))
# print(isinstance(a,Animal))
# print(isinstance(a,list))

"""
类属性和实例属性
实例属性：在__init__内定义并初始化
类属性：在类内，方法和属性的外面
单例模式：利用类属性改变new？？？
"""
#
# class Person(object):
#     # 类属性
#     country = '中国'
#     # 私有类属性，可以在类方法内通过cls访问私有类属性
#     __address = '亚洲'
#
#     # 实例属性
#     def __init__(self):
#         self.name = 'xiaoming'
#
#     # 实例方法/对象方法
#     def make1(self):
#         print('make1')
#
#     # 类方法，么偶一个类方法之前都要添加一个装饰器
#     @classmethod  # 装饰器，装饰类方法
#     def make(cls):  # 声明此方法为类方法
#         print('make')
#
# # 使用类属性：
# # 方式1：类名.类属性  或者  类对象.类属性
# print(Person.country)
# # 方式2：类名().类属性
# print(Person().country)
# # 方式3：对象调用
# p = Person()
# print(p.country)
#
# # 更改类属性
# p.country = '北京'
# print(p.country)
#
# # 调用类方法
# # 方式1：
# Person().make()
# # 方式2：
# Person.make()
# # 方式3：对象.类方法  对象调用类方法
# p.make()

# 类属性和实例方法区别
# 类属性不可以直接调用实例属性
# 1.类名可以调用类属性，但是不可以调用实例属性；
# 2.对象可以调用类属性和实例属性
# 3.类名().实例属性，ok

# 类方法和实例方法区别
# 类方法是类对象所拥有的方法；在类方法之前需要添加装饰器@classmethod
# 类方法的第一个参数必须是类对象（类名），一般以cls表示；可以通过实例对象和类对象进行调用（访问）
# 类方法用途：类方法还有一个用途就是可以对类属性进行修改，结果显示在用类方法对类属性修改之后，通过类对象和实例对象访问都发生了改变


"""
静态方法：不使用对象的方法
需要通过修饰器@staticmethod来进行修饰，静态方法不需要多定义参数，可以通过对象和类来访问。
不会用到对象的方法，都创建成静态方法，使代码速度更快
"""
class People(object):
    country = 'china'

    @staticmethod
    #静态方法
    def get_country():  # 没有self，即使有self也表示普通参数
        return People.country


p = People()
# 通过对象访问静态方法
p.get_country()

# 通过类访问静态方法
print(People.get_country())
"""
1.从类方法和实例方法以及静态方法的定义形式就可以看出来，类方法的第一个参数是类对象cls，
那么通过cls引用的必定是类对象的属性和方法；

2.实例方法的第一个参数是实例对象self，那么通过self引用的可能是类属性、也有可能是实例属性（这个需要具体分析），
不过在存在相同名称的类属性和实例属性的情况下，实例属性优先级更高。
类属性相当于全局，实例属性相当于局部

3.静态方法中不需要额外定义参数，因此在静态方法中引用类属性的话，必须通过类实例对象来引用
"""
